package com.bookworms.helloandengine.game.ui;

/*
 *This project covers the basics for a RPG environment. It takes care of the UI and gives two options:
 *Touch control or Digital Control. Both methods utilize A* Pathing to deal with collisions and basic movement
 * The project also takes care of Scene switching and includes transitions between the scenes. It, also, deals
 * with the loading of large TMX maps, if they are loaded repeatedly. Special Layers are also, taken care of. 
 * So far there are layers that animate and layers that the player can go under.    
 * Be Sure to look at the TMX files and see how the properties are used on Layers, Objects, and the Map itself
 */

import android.content.Context;
import android.opengl.GLU;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.BoundCamera;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.modifier.IEntityModifier;
import org.anddev.andengine.entity.modifier.PathModifier;
import org.anddev.andengine.entity.modifier.PathModifier.Path;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.opengl.util.GLHelper;
import org.anddev.andengine.util.constants.Constants;
import org.anddev.andengine.util.path.astar.AStarPathFinder;
import com.bookworms.helloandengine.game.UI;
import com.bookworms.helloandengine.game.utils.TMXMapUpdater;

import javax.microedition.khronos.opengles.GL10;
import java.util.ArrayList;
import java.util.List;

import static org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation.LANDSCAPE;

public class GameScreen extends BaseScreen implements IOnSceneTouchListener {
    protected static final long[] ANIMATE_DURATION = new long[]{200, 200, 200};
    protected static final int TILE_WIDTH = 32;
    protected static final int TILE_HEIGHT = 32;
    protected static final float TILE_ANIMATION_SPEED = 0.5f;
    // Controls the speed the character moves for touch events
    protected static final float TOUCH_SPEED = (float) 0.25;

    //Engine Fields
    protected static Scene mScene;
    protected static BoundCamera mBoundChaseCamera;

    protected static TiledTextureRegion mPlayerTextureRegion;
    private TextureRegion mFadeTextureRegion;

    //Sprite Control/UI/Pathing Fields
    protected static AnimatedSprite player;
    protected static int playerSpawnDirection;
    protected static org.anddev.andengine.util.path.Path walkingPath;
    protected static AStarPathFinder<TMXLayer> finder;
    protected static float[] playerFootCordinates;
    protected static Path mCurrentPath;
    protected static boolean isWalking;
    protected static int mWaypointIndex;
    protected static PathModifier mMoveModifier;
    protected static IEntityModifier mPathTemp;

    //TMX Fields
    protected static TMXLoader mTmxLoader;
    protected static TMXTiledMap mTMXTiledMap;
    protected static TMXTiledMap mLargeTMXMap;
    protected static TMXLayer TMXMapLayer;
    protected static TMXLayer mTopLayer;
    protected static TMXLayer mAnimateLayer;
    protected static TMXTile playerLocationTile;

    //Lists
    protected static List<TMXTile> mCollideTiles;
    protected static List<TMXTile> ExitTiles;
    protected static ArrayList<Integer> MapNumber;
    protected static List<TMXTile> animatedTiles;
    protected static List<TMXTile> playerSpawnTiles;
    protected static ArrayList<Integer> LinkNumber;
    protected static List<TMXTile> propertyTiles;
    protected static ArrayList<Integer> propertyIndex;

    //Indexes
    protected static int mCurrentMapIndex;
    protected static int mLargeTMXIndex = 1000;
    protected static int mLinkIndex;

    //Initial values; These should be initialized from a separate file that was saved before finish();
    protected static float InitialplayerSpawnX = TILE_WIDTH * 5;
    protected static float InitialplayerSpawnY = TILE_HEIGHT * 5;

    //Used to get object tiles in TMX
    protected static int ObjectX;
    protected static int ObjectY;
    protected static int ObjectWidth;
    protected static int ObjectHeight;

    protected static boolean EnableBounds = true;
    protected static boolean AssetsAttached;
    protected static boolean MapIsLoading;
    protected static boolean mTouchLocked;
    protected static boolean UpdateTiles;

    protected static Sprite mFadeScreen;
    protected static Context mContext;

    @Override
    public Engine onLoadEngine() {
        super.onLoadEngine();
        mBoundChaseCamera = getPlayerBoundCamera();
        //This is used in the TMXMapUpdater() class in the getTMXMap() Mathod
        mContext = getApplicationContext();
        RatioResolutionPolicy resolutionPolicy = new RatioResolutionPolicy(mCameraWidth, mCameraHeight);
        EngineOptions options = new EngineOptions(true, LANDSCAPE, resolutionPolicy, mBoundChaseCamera);
        // Sets the touch interactions to get processed during the update thread??
        options.getTouchOptions().setRunOnUpdateThread(true);
        return new Engine(options);
    }

    private BoundCamera getPlayerBoundCamera() {
        return new BoundCamera(0, 0, mCameraWidth, mCameraHeight) {
            //Forces the camera to move in integer steps. Helps prevent artifacts from appearing when scrolling
            @Override
            public void onApplySceneMatrix(GL10 pGL) {
                GLHelper.setProjectionIdentityMatrix(pGL);
                GLU.gluOrtho2D(pGL, (int) this.getMinX(), (int) this.getMaxX(), (int) this.getMaxY(), (int) this.getMinY());
            }
        };
    }

    @Override
    public void onLoadResources() {
        TextureRegionFactory.setAssetBasePath("gfx/");
        Texture mPlayerTexture = new Texture(128, 128, TextureOptions.DEFAULT);
        mPlayerTextureRegion = TextureRegionFactory.createTiledFromAsset(mPlayerTexture, this, "player.png", 0, 0, 3, 4);
        Texture fadeTexture = new Texture(1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        mFadeTextureRegion = TextureRegionFactory.createFromAsset(fadeTexture, getApplicationContext(), "fade_background.png", 0, 0);
        mEngine.getTextureManager().loadTextures(mPlayerTexture, fadeTexture);
    }

    @Override
    public Scene onLoadScene() {
        mScene = super.onLoadScene();
        mScene.setBackground(new ColorBackground(0f, 0f, 0f));
        mTmxLoader = new TMXLoader(this, mEngine.getTextureManager(), TextureOptions.NEAREST, null);
        mFadeScreen = new Sprite(0, 0, mFadeTextureRegion);
        TMXMapUpdater.loadAndAttachAssets(0);
        mScene.registerUpdateHandler(getSceneUpdateHandler());
        mScene.registerUpdateHandler(getTileAnimationTimerHandler());
        mScene.setOnSceneTouchListener(this);
        return mScene;
    }

    private TimerHandler getTileAnimationTimerHandler() {
        return new TimerHandler(TILE_ANIMATION_SPEED, true, new ITimerCallback() {
            @Override
            public void onTimePassed(final TimerHandler pTimerHandler) {
                if (!MapIsLoading) {
                    TMXMapUpdater.doProperty1(playerLocationTile);    //Do the random property
                    TMXMapUpdater.doTileAnimations();
                }
            }
        });
    }

    private IUpdateHandler getSceneUpdateHandler() {
        return new IUpdateHandler() {
            @Override
            public void reset() {
            }
            @Override
            public void onUpdate(final float pSecondsElapsed) {
                if (UpdateTiles) {    //Allows the tiles to get the player location as soon as possible
                    // Get the scene-coordinates of the tile center.
                    playerFootCordinates = player.convertLocalToSceneCoordinates(16, 16);
                    //Get the tile where the center of the current tile is.
                    playerLocationTile = TMXMapLayer.getTMXTileAt(playerFootCordinates[Constants.VERTEX_INDEX_X],
                            playerFootCordinates[Constants.VERTEX_INDEX_Y]);
                }
                //If the TMX map is loading then the scene updates will freeze
                if (!MapIsLoading) {
                    //Gets the index of the current map
                    mCurrentMapIndex = Integer.parseInt(mTMXTiledMap.getTMXTiledMapProperties().get(0).getValue());
                    //This updates the TMX map when the sprite exits or enters the scene
                    TMXMapUpdater.updateTMXMap();
                }
            }
        };
    }

    @Override
    public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
        //The constraints on the TouchEvents are there to prevent errors that occur when the screen is touched while loading
        //or if the scene is touched outside of the TMXMap
        if (!MapIsLoading) {
            if (pSceneTouchEvent.isActionDown() && pSceneTouchEvent.getX() < TMXMapLayer.getWidth()
                    && pSceneTouchEvent.getY() < TMXMapLayer.getHeight() && pSceneTouchEvent.getX() > 0
                    && pSceneTouchEvent.getY() > 0 && !mTouchLocked) {
                //Walks to the touched area
                UI.walkToSelectedPoint(pSceneTouchEvent.getX(), pSceneTouchEvent.getY(), pScene);
                //This is set to true in the GeneralUI
                return true;
            }
        }
        return false;
    }
}